﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed
#pragma once

#include "GcmpModelInterface.h"
#include "IElement.h"
#include "ModelViewEnums.h"
#include <vector>

namespace gcmp
{
    class IGraphicsElementShape;
    class IGraphicsPlane;
    class Box3d;
    class Coordinate3d;
    class Vector3d;
    /// \brief 分割区域返回的错误类型
    enum class SplitErrorType : int32_t
    {
        NoError = 0,            ///< 没有错误
        NoRectViewport = 1,     ///< 没有默认矩形裁剪框可拆分
        SplitTypeConflict,      ///< 拆分类型冲突，默认仅支持水平或竖直拆分，已经水平拆分的，不能支持竖直拆分
        SplitRegionTooSmall,    ///< 分割区域范围太小
        SplitRegionOutOfRange,  ///<分割区超出裁剪范围
        SplitRegionGapToolSmall, ///<拆分裁剪区域的距离小于最小间距
        FoldRegionIsEmpty,      ///< 折叠区域为空
        FoldRegionTooLarge,     ///< 折叠区域超出裁剪区域范围     
        RotatedViewCanNotSplit, ///< 旋转的视图不支持拆分裁剪框
        Unknown,                ///< 错误类型未知
    };
    /// \brief 点在视图裁剪框的位置
    enum class EnSplitType : int32_t
    {
        Unknown = 0,   ///< 未知类型
        Horizontal = 1,   ///< 水平拆分
        Vertical = 2,   ///< 竖直拆分
    };

    /// \brief 裁剪区域边的类型
    enum EnRegionEdgePosition
    {
        REPLeft = 0,      ///< 裁剪框的左边
        REPRight = 1,    ///< 裁剪框的右边
        REPTop = 2,      ///< 裁剪框的上边
        REPBottom = 3 ///< 裁剪框的底边
    };
    /// \brief 夹点在视图裁剪框的位置
    enum class EnSplitViewPortAuxiliaryPoint : int32_t
    {
        Left = 0,     ///< 左侧夹点
        Right = 1,    ///< 右侧夹点
        Top = 2,      ///< 顶部夹点
        Bottom = 3,   ///< 底部夹点

        LeftTopSplit = 4,  ///< 左上拆分点
        RightTopSplit = 5, ///< 右上拆分点
        LeftBottomSplit = 6,  /// 左下拆分点
        RightBottomSplit = 7,  ///右下拆分点

        Annotation_Left = 8,        ///< 左侧注释裁剪夹点
        Annotation_Right = 9,      ///< 右侧注释裁剪夹点
        Annotation_Top = 10,        ///< 顶部注释裁剪夹点
        Annotation_Bottom = 11,  ///< 底部注释裁剪夹点
    };

    /// \brief 折叠点在视图裁剪框的位置
    enum class EnSplitViewPortFoldPoint : int32_t
    {
        MinFoldPoint = 0,   ///< 沿着拆分方向上最小值位置
        MaxFoldPoint = 1,   ///< 沿着拆分方向上最大值位置
    };

    /// \brief 视图裁剪范围
    class GCMP_MODEL_INTERFACE_EXPORT IViewClipRange : public IElement
    {
        DEFINE_CAST_DERIVED(gcmp::IViewClipRange, gcmp::IElement);

    public:


        /// \brief 裁剪面是否可见
        /// \return 是否裁剪
        virtual bool IsClipVisible() const = 0;

        /// \brief 设置裁剪面是否可见
        /// \return void
        virtual void SetClipVisible(bool isVisible) = 0;

        /// \brief 得到裁剪类型
        /// \return EnSplitType 裁剪类型  
        virtual EnSplitType GetSplitType() const = 0;

        /// \brief 获取折叠状态
        /// \return bool true，折叠状态；false，展开状态
        virtual bool IsFold() const = 0;

        /// \brief 获取矩形裁剪范围的裁剪面的偏移
        /// \param leftOffset 基于视图原点的左偏移
        /// \param rightOffset 基于视图原点的右偏移
        /// \param upOffset 基于视图原点的上偏移
        /// \param downOffset 基于视图原点的下偏移
        /// \return 是否获取成功
        virtual bool GetRectViewClipRange(double& leftOffset, double& rightOffset, double& upOffset, double& downOffset) const = 0;

        /// \brief 获取折叠后矩形裁剪范围的裁剪面的偏移（在视图中显示的范围）
        /// \param leftOffset 基于视图原点的左偏移
        /// \param rightOffset 基于视图原点的右偏移
        /// \param upOffset 基于视图原点的上偏移
        /// \param downOffset 基于视图原点的下偏移
        /// \return 是否获取成功
        /// \note 如果裁剪框不是折叠状态则返回默认裁剪框的范围
        virtual bool GetFoldViewClipRange(double& leftOffset, double& rightOffset, double& upOffset, double& downOffset) const = 0;

        /// \brief 更新矩形裁剪范围的裁剪面的偏移
        /// \param leftOffset 基于视图原点的左偏移
        /// \param rightOffset 基于视图原点的右偏移
        /// \param upOffset 基于视图原点的上偏移
        /// \param downOffset 基于视图原点的下偏移
        /// \return 是否更新成功
        virtual bool UpdateRectViewClipRange(double leftOffset, double rightOffset, double upOffset, double downOffset) = 0;

        /// \brief （临时，可能移除）获取视图范围(包括视口、顶面、剖切面、底面、深度面、剖面盒)关联更新RdId
        /// \return 视图范围关联更新RdId
        virtual RegenDataId GetRangeUpdatedRdId() const = 0;

        /// \brief 标记视图范围已发生改变
        virtual void MarkRangeUpdatedRdId() = 0;

        /// \brief 获取ModelView的ElementId
        /// \return ModelView的ElementId
        virtual ElementId GetModelViewId() const = 0;

        /// \brief 裁剪区域的最小范围（不设置将采用默认值）
        /// \param[in]    double minClipRegionRange
        virtual void SetRegionMinRange(double minClipRegionRange) = 0;

        /// \brief 裁剪区域的最小范围
        /// \return       double
        virtual double GetRegionMinRange() const =0;

        /// \brief 裁剪区域直接的最小距离（不设置将采用默认值）
        /// \param[in]    double minClipRegionRange
        /// \return 如果裁剪框已拆分，最小间距不能大于裁剪区域之间的实际距离，否则返回false
        virtual bool SetRegionMinGap(double minClipRegionRange) = 0;

        /// \brief 裁剪区域直接的最小距离
        /// \return       double
        virtual double GetRegionMinGap() const = 0;

        /// \brief 拆分矩形裁剪框，视图裁剪必须开启后有效
        /// \param splitDirection 拆分方向(仅支持平行-视图Up方向，或垂直-视图Rignt方向）
        /// \param widthStart 拆分区域初始点和拆分方向确定的线，相对视图原点的偏移
        /// \param widthEnd   拆分区域终止点和拆分方向确定的线，相对视图原点的偏移
        /// \return 拆分结果
        virtual SplitErrorType SplitRegion(const Vector3d& splitDirection, double widthStart, double widthEnd) = 0;

        /// \brief 合并裁剪区域
        /// \return 合并结果
        /// \note 当合并后只有一个裁剪区域时，删除裁剪区域，拆分类型设为unknown，使用默认矩形裁剪框
        virtual bool MergeRegions() = 0;

        /// \brief 展开所有区域
        ///
        /// \return 展开是否成功
        virtual bool UnFoldAllRegions() = 0;

        /// \brief 折叠所有区域
        ///
        /// \return 折叠是否成功
        virtual bool FoldAllRegions() = 0;

        /// \brief 删除所有裁剪区域
        /// 
        virtual void ClearRegions() = 0;

        /// \brief 获取构建与裁剪框的位置关系
        ///  
        /// \param elementId 构建的Id
        /// \return 如果能够在当前可见视图缓存中找到构件的Grep，则返回构建与裁剪框的位置关系
        /// \note 如果是模型，则返回模型与模型裁剪框的位置关系；如果是注释，则返回注释与注释裁剪框的位置关系
        /// 如果构件在当前视图可见Grep缓存中找不到，则不计算。因为直接从构件获取的modelGrep/viewGrep未经过深度裁剪，其计算结果可能不对，如一个顶面大地面小的融合体
        virtual ModelViewRangeRelation GetViewRangeRelation(const ElementId& elementId) = 0;

        /// \brief 获取模型裁剪框的包围盒
        ///
        /// \return 返回模型裁剪框的包围盒
        /// \note 如果裁剪框被拆分，包围盒依然是未拆分的整体裁剪框的范围
        virtual TiltBox3d GetModelClipRangeBox() = 0;

        /// \brief 获取注释裁剪框的包围盒
        ///
        /// \return 返回注释裁剪框的包围盒
        virtual TiltBox3d GetAnnotationClipRangeBox() = 0;

        /// \brief 获取Implementation Uid
        ///
        /// \return UniIdentity 返回ImplementationUid
        static UniIdentity GetImplementationUid();

        /// \brief 通过ElementId返回IViewClipRange指针
        ///
        /// \return IViewClipRange指针
        static IViewClipRange* GetViewClipRange(const IDocument* pDoc, const ElementId& elementIdViewClipRange);
        
        virtual ~IViewClipRange();
    };
    
}

